﻿using System;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.PowerPoint.STAMP.Command;
using Microsoft.Office.PowerPoint.STAMP.Core;
using Microsoft.Office.PowerPoint.STAMP.Properties;
using Shape = Microsoft.Office.Interop.PowerPoint.Shape;

namespace Microsoft.Office.PowerPoint.STAMP
{
    /// <summary>
    /// CCAI Ribbon class
    /// </summary>
    [ComVisible(true)]
    public class StampRibbon : IRibbonExtensibility
    {
        private static IRibbonUI _ribbon;

        #region IRibbonExtensibility Members

        /// <summary>
        /// System callback to retrieve the ribbon definition for the AddIn to include in the
        /// application UI.
        /// </summary>
        /// <param name="ribbonId">The id of the ribbon being requested.</param>
        /// <returns>The ribbon definition.</returns>
        public string GetCustomUI(string ribbonId)
        {
            return GetResourceText("Microsoft.Office.PowerPoint.STAMP.StampRibbon.xml");
        }

        #endregion

        #region Ribbon Load Callback

        /// <summary>
        /// System event triggered when the ribbon is loaded.
        /// </summary>
        /// <param name="ribbonUi">The <see cref="IRibbonUI"/> object being created.</param>
        public void Ribbon_Load(IRibbonUI ribbonUi)
        {
            _ribbon = ribbonUi;
        }

        #endregion

        #region Button Click Callbacks
        /// <summary>
        /// Aligns all captions on the currently selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        public void AlignCaptionsOnAction(IRibbonControl control)
        {
            var application = Globals.ThisAddIn.Application;
            Slide activeSlide = application.ActiveWindow.View.Slide;
            Shape shape = application.ActiveWindow.Selection.ShapeRange[1];

            CaptionManager manager = new CaptionManager(activeSlide, shape);
            manager.AlignCaptions();
        }

        /// <summary>
        /// Prompts the user for a file from which to load a set of captions and applies them to 
        /// the selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        public void AddCaptionsOnAction(IRibbonControl control)
        {
            new ImportCommand().Execute();
            
            ForceInvalidate();
        }


        /// <summary>
        /// Displays the caption editor form to allow the user to create captions for the selected
        /// media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        public void CreateCaptionsOnAction(IRibbonControl control)
        {
            new EditorCommand().Execute();

            ForceInvalidate();
        }

        /// <summary>
        /// Loads the current set of captions for the shape and displays them in the caption editor.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        public void EditCaptionsOnAction(IRibbonControl control)
        {
            new EditorCommand().Execute();
            
            ForceInvalidate();
        }

        /// <summary>
        /// Removes all captions from the selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        public void RemoveCaptionsOnAction(IRibbonControl control)
        {
            if (MessageBox.Show(
                Resources.CCAIRibbon_RemoveCaptionsOnAction_MessageBox_Text,
                Resources.CCAIRibbon_RemoveCaptionsOnAction_MessageBox_Header, MessageBoxButtons.YesNoCancel) == DialogResult.Yes)
            {

                var application = Globals.ThisAddIn.Application;
                Slide activeSlide = application.ActiveWindow.View.Slide;
                Shape shape = application.ActiveWindow.Selection.ShapeRange[1];

                CaptionManager manager = new CaptionManager(activeSlide, shape);

                int captionCount = manager.CaptionItemsList.CaptionItems.Count;
                if (captionCount > Settings.Default.ProcessingNotificationLimit)
                {

                    var form = new Progress(100);
                    form.Show();

                    form.Update(1,
                                        Resources.
                                            CCAIRibbon_RemoveCaptionsOnAction_DeleteAnimations_Phase_one_of_deleting_captions);
                    manager.DeleteAnimations();

                    form.Update(33,
                                        Resources.
                                            CCAIRibbon_RemoveCaptionsOnAction_DeleteBookmarks_Phase_two_of_deleting_captions);
                    manager.DeleteBookmarks();

                    form.Update(66,
                                        Resources.
                                            CCAIRibbon_RemoveCaptionsOnAction_DeleteShapes_Phase_three_of_deleting_captions);
                    manager.DeleteShapes();

                    if (manager.HasSavedCaptions)
                    {
                        form.Update(99,
                                            Resources.
                                                CCAIRibbon_RemoveCaptionsOnAction_DeleteShapes_Phase_four_of_deleting_captions);
                        manager.DeleteCaptionIdTag();
                    }

                    form.Close();
                }
                else
                {
                    manager.RemoveSlideCaptions();
                }


                ForceInvalidate();
            }
        }

        /// <summary>
        /// Displays the captions associated to the media shape that were previously hidden.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        public void ShowCaptionsOnAction(IRibbonControl control)
        {
            var application = Globals.ThisAddIn.Application;
            Slide activeSlide = application.ActiveWindow.View.Slide;
            Shape shape = application.ActiveWindow.Selection.ShapeRange[1];

            CaptionManager manager = new CaptionManager(activeSlide, shape);
            manager.ShowCaptions();

            ForceInvalidate();
        }

        /// <summary>
        /// Hidea all captions associated with the selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        public void HideCaptionsOnAction(IRibbonControl control)
        {
            var application = Globals.ThisAddIn.Application;
            Slide activeSlide = application.ActiveWindow.View.Slide;
            Shape shape = application.ActiveWindow.Selection.ShapeRange[1];

            CaptionManager manager = new CaptionManager(activeSlide, shape);
            manager.HideCaptions();

            ForceInvalidate();
        }

        #endregion

        #region Button Enabled Callbacks

        /// <summary>
        /// Set the enabled state of the add captions button based on the currently selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        /// <returns>True if there are no existing captions.</returns>
        public bool AddCaptionsGetEnabled(IRibbonControl control)
        {
            return !CaptionManager.ActiveShapeHasCaptions();
        }

        /// <summary>
        /// Set the enabled state of the create captions button based on the currently selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        /// <returns>True if there are no existing captions.</returns>
        public bool CreateCaptionsGetEnabled(IRibbonControl control)
        {
            return !CaptionManager.ActiveShapeHasCaptions();
        }

        /// <summary>
        /// Set the enabled state of the edit captions button based on the currently selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        /// <returns>True if there are existing captions.</returns>
        public bool EditCaptionsGetEnabled(IRibbonControl control)
        {
            return CaptionManager.ActiveShapeHasCaptions();
        }

        /// <summary>
        /// Set the enabled state of the align captions button based on the currently selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        /// <returns>True if there are existing captions.</returns>
        public bool AlignCaptionsGetEnabled(IRibbonControl control)
        {
            return CaptionManager.ActiveShapeHasCaptions();
        }

        /// <summary>
        /// Set the enabled state of the remove captions button based on the currently selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        /// <returns>True if there are existing captions.</returns>
        public bool RemoveCaptionsGetEnabled(IRibbonControl control)
        {
            return CaptionManager.ActiveShapeHasCaptions();
        }

        /// <summary>
        /// Set the enabled state of the hide captions button based on the currently selected media shape
        /// and if there are hidden captions.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        /// <returns>True if there are existing captions that are not already hidden.</returns>
        public bool HideCaptionsGetEnabled(IRibbonControl control)
        {
            // TODO: include check for already hidden 
            return CaptionManager.ActiveShapeHasCaptions() && !CaptionManager.MediaCaptionsHidden();
        }

        /// <summary>
        /// Set the enabled state of the show captions button based on the currently selected media shape.
        /// </summary>
        /// <param name="control">The <see cref="IRibbonControl"/> that raised the event.</param>
        /// <returns>True if there are existing captions that are already hidden.</returns>
        public bool ShowCaptionsGetEnabled(IRibbonControl control)
        {
            // TODO: include check for already hidden 
            return CaptionManager.ActiveShapeHasCaptions() && CaptionManager.MediaCaptionsHidden();
        }

        #endregion

        #region Helpers

        /// <summary>
        /// Retrieves the ribbon definition for the UI rendering.
        /// </summary>
        /// <param name="resourceName">The name of the ribbon for this AddIn.</param>
        /// <returns>The ribbon definition.</returns>
        private static string GetResourceText(string resourceName)
        {
            Assembly asm = Assembly.GetExecutingAssembly();
            string[] resourceNames = asm.GetManifestResourceNames();
            for (int i = 0; i < resourceNames.Length; ++i)
            {
                if (string.Compare(resourceName, resourceNames[i], StringComparison.OrdinalIgnoreCase) == 0)
                {
                    using (
                        StreamReader resourceReader = new StreamReader(asm.GetManifestResourceStream(resourceNames[i])))
                    {
                        if (resourceReader != null)
                        {
                            return resourceReader.ReadToEnd();
                        }
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Invalidates the ribbon to ensure that the buttons are refreshed.  Specifically for the enabled state.
        /// </summary>
        public static void ForceInvalidate()
        {
            if (_ribbon != null)
            {
                CaptionManager.CheckShapeForCaptionsAfterChange();
                _ribbon.Invalidate();
            }
        }

        /// <summary>
        /// Gets the image for a specific button.
        /// </summary>
        /// <param name="control">Control that needs the image.</param>
        /// <returns>Bitmap image.</returns>
        public Bitmap GetImage(IRibbonControl control)
        {
            switch (control.Tag)
            {
                case "imgAddCaptions": return new Bitmap(Resources._8562_AddCaptions_HH);
                case "imgAddCaptionsSmall": return new Bitmap(Resources._8562_AddCaptions_HS);
                case "imgEditCaptions": return new Bitmap(Resources._14977_EditClosedCaptions_HH);
                case "imgAlignCaptions": return new Bitmap(Resources._9169_AlignCaptions_HH);
                case "imgHideCaptionsSmall": return new Bitmap(Resources._9174_HideCaptions_HS);
                case "imgShowCaptionsSmall": return new Bitmap(Resources.ShowCaptions_HS);
                case "imgRemoveCaptionsSmall": return new Bitmap(Resources._8574_RemoveCaptions_HS);
                case "imgFolderSmall": return new Bitmap(Resources.Folder_HS);
                case "imgEditCaptionsSmall": return new Bitmap(Resources.EditClosedCaptions_HS);
            }
            return null;
        }

        #endregion
    }
}
